package dao

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"gorm.io/gorm"
	"strconv"
	"time"
	"web_api_gin/core"
	"web_api_gin/dto"
	"web_api_gin/entity"
)

var SysRole = SysRoleDao{}

type SysRoleDao struct {
}

//获取分页数据
func (d *SysRoleDao) GetList(ctx *gin.Context, searchParams *dto.SysRoleGetListReq) ([]*entity.SysRole, int64, error) {
	var total int64
	list := ([]*entity.SysRole)(nil)
	tx := DB(ctx).Model(&entity.SysRole{})
	if searchParams.Name != "" {
		tx = tx.Where("name like ?", "%"+searchParams.Name+"%")
	}
	if searchParams.DisplayName != "" {
		tx = tx.Where("display_name like ?", "%"+searchParams.DisplayName+"%")
	}
	rs := tx.Count(&total).Order("order_num ASC, role_id ASC").Limit(int(searchParams.PageSize)).Offset(int((searchParams.PageNo - 1) * searchParams.PageSize)).Find(&list)
	return list, total, rs.Error
}

//获取指定用户的角色ID数组集
func (d *SysRoleDao) GetUserRoleIds(ctx *gin.Context, userId uint32) []uint32 {
	var list []entity.SysRoleUser
	var userRoleIds []uint32
	//用户-角色中间表记录数据
	DB(ctx).Where(&entity.SysRoleUser{UserId: userId}).Find(&list)
	for _, v := range list {
		userRoleIds = append(userRoleIds, v.RoleId)
	}
	return userRoleIds
}

//通过用户ID获取角色列表
func (d *SysRoleDao) GetRoleListByUserId(ctx *gin.Context, userId uint32) ([]*entity.SysRole, error) {
	//用户-角色中间表记录数据
	userRoleIds := d.GetUserRoleIds(ctx, userId)
	roleList := ([]*entity.SysRole)(nil)
	//角色列表
	result := DB(ctx).Where("role_id in ?", userRoleIds).Find(&roleList)
	return roleList, result.Error
}

//获取用户角色列表（缓存）
func (d *SysRoleDao) GetUserRoleListCache(ctx *gin.Context, userData *entity.SysUsers, isRefresh bool) ([]string, []uint32, error) {
	//角色名称缓存KEY
	cacheKeyRoleName := "sys_user_role_name_list:" + strconv.FormatUint(uint64(userData.Id), 10)
	userRoleNameJsonStr, errRoleNames := core.Redis.Get(ctx, cacheKeyRoleName).Result()
	//角色ID缓存KEY
	cacheKeyRoleId := "sys_user_role_id_list:" + strconv.FormatUint(uint64(userData.Id), 10)
	userRoleIdJsonStr, errRoleIds := core.Redis.Get(ctx, cacheKeyRoleId).Result()
	var (
		userRoleNameList []string //用户角色名称列表
		userRoleIdList   []uint32 //用户角色ID列表
	)
	if errRoleNames == redis.Nil || errRoleIds == redis.Nil || isRefresh == true {
		userRoleList, err := d.GetRoleListByUserId(ctx, userData.Id)
		if err != nil {
			return nil, nil, err
		}
		//收集用户权限名称列表和权限ID列表
		for _, roles := range userRoleList {
			userRoleNameList = append(userRoleNameList, roles.Name)
			userRoleIdList = append(userRoleIdList, roles.RoleId)
		}
		//缓存角色列表
		userRoleNameJsonStr, _ := json.Marshal(userRoleNameList)
		if err := core.Redis.Set(ctx, cacheKeyRoleName, userRoleNameJsonStr, 2*time.Hour).Err(); err != nil {
			return nil, nil, err
		}
		//缓存角色ID列表
		userRoleIdJsonStr, _ := json.Marshal(userRoleIdList)
		if err := core.Redis.Set(ctx, cacheKeyRoleId, userRoleIdJsonStr, 2*time.Hour).Err(); err != nil {
			return nil, nil, err
		}
		return userRoleNameList, userRoleIdList, nil
	}
	if err := json.Unmarshal([]byte(userRoleNameJsonStr), &userRoleNameList); err != nil {
		return nil, nil, err
	}
	if err := json.Unmarshal([]byte(userRoleIdJsonStr), &userRoleIdList); err != nil {
		return nil, nil, err
	}
	return userRoleNameList, userRoleIdList, nil
}

// 获取角色名称列表
func (d *SysRoleDao) GetRoleNameListByUserId(ctx *gin.Context, userId uint32) []string {
	var list []*entity.SysRole
	var roleNameList []string
	//用户-角色中间表记录数据
	userRoleIds := d.GetUserRoleIds(ctx, userId)
	DB(ctx).Where(userRoleIds).Find(&list)
	for _, v := range list {
		roleNameList = append(roleNameList, v.Name)
	}
	return roleNameList
}

//保存角色数据
func (d *SysRoleDao) SaveRole(ctx *gin.Context, data *entity.SysRole) error {
	//使用事务闭包
	return DB(ctx).Transaction(func(tx *gorm.DB) error {
		if data.RoleId != 0 {
			if err := tx.Model(&entity.SysRole{}).Where("role_id = ?", data.RoleId).Updates(&data).Error; err != nil {
				return err
			}
		} else {
			if err := tx.Create(&data).Error; err != nil {
				return err
			}
		}
		//保存角色关联权限数据
		//先删除已有数据（硬删）
		if err := tx.Unscoped().Where("role_id = ?", data.RoleId).Delete(&entity.SysPermissionRole{}).Error; err != nil {
			return err
		}
		//批量添加关联数据
		var permRoleList []entity.SysPermissionRole
		var permIds []string
		json.Unmarshal(data.PermIds, &permIds)
		if len(permIds) > 0 {
			for _, permId := range permIds {
				permIdFormat, _ := strconv.ParseUint(string(permId), 10, 32)
				permRoleList = append(permRoleList, entity.SysPermissionRole{RoleId: data.RoleId, PermId: uint32(permIdFormat)})
			}
			if err := tx.Create(&permRoleList).Error; err != nil {
				return err
			}

		}
		// 返回 nil 提交事务
		return nil
	})
}

//删除角色
func (d *SysRoleDao) DelRole(ctx *gin.Context, roleIds []uint32) error {
	return DB(ctx).Transaction(func(tx *gorm.DB) error {
		//删除角色数据
		if err := DB(ctx).Delete(&entity.SysRole{}, roleIds).Error; err != nil {
			return err
		}
		//删除相关权限数据（硬删）
		if err := tx.Unscoped().Where("role_id IN ?", roleIds).Delete(&entity.SysPermissionRole{}).Error; err != nil {
			return err
		}
		// 返回 nil 提交事务
		return nil
	})
}
